
import { getHostiles } from "../../../global/map";
import { GroupWork } from "../terminal/work";
import { jobGoto } from "../../../job/goto";
import { jobAttack } from "../../../job/attack";
import { getApproprateEnergy, getMaxEnergy, spawnCreep } from "../../../role/spawn";
import { jobSpread } from "../../../job/spread";

export class ClusterDefenders extends GroupWork{
    get maxSize(){
        return this.targets.length+1;
    }
    get attackersCount(){
        if(this._attackersCount !== undefined){
            return this._attackersCount;
        }
        let ans = 0;
        for(let creep of this.creeps){
            if(creep.memory.role === "attacker"){
                ans++;
            }
        }
        return this._attackersCount = ans;
    }
    get rangedAttackersCount(){
        return this.size - this.attackersCount;
    }

    /**
     * @returns {(AnyCreep|AnyStructure)[]}
     */
    get targets(){
        if(this.__targets !== undefined){
            return this.__targets;
        }

        let invaderRooms = [];
        this.__targets = getHostiles(this.spawnRoom).filter((target)=>{
            if(target.room.name === this.spawnRoomName){
                return true;
            }
            if(target instanceof StructureInvaderCore && 
                target.room.controller === undefined)
            {
                invaderRooms.push(target.room);
                return false;
            }
            return true;
        });
        this.__targets = this.__targets.filter((target)=>{
            if(target.room.name === this.spawnRoom.name){
                return true;
            }
            if(target.owner.username !== "Invader"){
                return false;
            }
            const isInInvaderColony = invaderRooms.some((room)=>room.name === target.room.name);
            return !isInInvaderColony;
        });

        return this.__targets;
    }
    serialize(){
        return {
            super:super.serialize(),
        }
    }
    deserialize(obj){
        super.deserialize(obj.super);
        return this;
    }

    spawnAttacker(){
        const energy = this.targets.length === 0
            ? getApproprateEnergy(this.spawnRoom)
            : getMaxEnergy(this.spawnRoom);
        const newCreep = spawnCreep(this.spawnRoom,{
            require: [MOVE, ATTACK],
            move: .50,
            attack: .50,
        },{
            memory: {
                role: 'attacker',
            }
        }, energy);
        if(!(newCreep instanceof Creep)){
            return newCreep;
        }
        this.addCreep(newCreep);
        return OK;
    }
    spawnRangedAttacker(){
        const newCreep = spawnCreep(this.spawnRoom,{
            require: [MOVE, RANGED_ATTACK],
            move: .50,
            ranged_attack: .50,
        },{
            memory: {
                role: 'ranged_attacker',
            }
        }, getMaxEnergy(this.spawnRoom));
        if(!(newCreep instanceof Creep)){
            return newCreep;
        }
        this.addCreep(newCreep);
        return OK;
    }

    spawn(){
        if(this.attackersCount < 2){
            return this.spawnAttacker();
        }
        return this.spawnRangedAttacker();
    }

    creepRun(creep){
        let targets = this.targets;
        
        if(creep.memory.role === "attacker"){
            return jobAttack.run(creep, targets, {visualizePathStyle:{stroke:"#ff0000"}});
        }

        // ranged_attackers
        if(targets.length===0){
            return jobSpread.run(creep);
        }
        jobGoto.run(creep, targets, {visualizePathStyle:{stroke:"#ff0000"}});

        let ret;
        for(let target of targets){
            if(target.pos.isNearTo(creep)){
                ret = creep.rangedMassAttack();
            }else{
                ret = creep.rangedAttack(target);
            }
            if(ret === OK){
                break;
            }
        }
        return ret;
    }
}
